package com.fuint.utils.syb;

import cn.hutool.json.JSONUtil;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.Map;
import java.util.TreeMap;

import static com.fuint.utils.syb.SybConstants.*;

public class SybPayUtils {

    // TODO 注意：看原代码中用的是 application/x-www-form-urlencoded

    private RestTemplate restTemplate = new RestTemplate();

    public static String getAppKey() {
        String appkey = "";
        if (SybConstants.SIGN_TYPE.equals("RSA")) {
            appkey = SybConstants.SYB_RSA_PRIVATE_KEY;
        } else if (SybConstants.SIGN_TYPE.equals("SM2")) {
            appkey = SybConstants.SYB_SM2_PRIVATE_KEY;
        } else {
            appkey = SybConstants.SYB_MD5_APP_KEY;
        }
        return appkey;
    }

    public static <K, V> MultiValueMap<K, V> convert(TreeMap<K, V> treeMap) {
        // 创建一个 LinkedMultiValueMap 实例
        MultiValueMap<K, V> multiValueMap = new LinkedMultiValueMap<>();

        // 遍历 TreeMap 中的每个键值对
        for (Map.Entry<K, V> entry : treeMap.entrySet()) {
            K key = entry.getKey();
            V value = entry.getValue();
            // 将键值对添加到 LinkedMultiValueMap 中
            multiValueMap.add(key, value);
        }

        return multiValueMap;
    }

    // @param randomstr    随机字符串（否 23位）
    // @param expiretime   订单失效时间（订单截止支付时间，yyyyMMddHHmmss）

    /**
     * 支付
     *
     * @param trxamt        <Long> 交易金额（分）
     * @param sn            <String> 商户交易订单号（保证商户平台唯一）
     * @param body          <String> 订单标题（订单商品名，为空则以商户名代替）（最大100字节，UTF8编码，一个中文3字节）
     * @param remark        <String> 备注（160字节，禁止出现 +, 空格, /, ?, %, #, $, =)
     * @param acct          <String> 支付平台用户标识（JS支付时使用，微信支付:微信openid, 支付宝:用户user_id, 微信小程序:小程序openid)
     * @param notifyUrl     <String> 交易回调地址 http/https
     * @param limitPay      <String> 支付限制 no_credit 指定不能使用信用卡支付（对微信支付/支付宝有效，仅支持no_credit）
     * @param appid         <String> 微信小程序/微信公众号/APP的appid
     * @param subbranch     <String> 通联系统门店号
     * @param paytype       <String> 交易方式（非必填）
     * @param validTime     <String> 订单有效时间（订单有效时间，单位分，不填默认5分钟，最大1440分钟）（非必填）
     * @param goods_tag     <String> 订单优惠标识（用于区分订单是否可以享受优惠，只对微信支付有效）（非必填）
     * @param benefitdetail <String> 微信单品优惠,支付宝智慧门店,支付宝单品优惠
     * @param chnlstoreid   <String> 商户再支付渠道端的门店编号（支付宝：支付宝门店号，微信：微信门店号）（非必填）
     * @param idno          <String> 身份证，实名交易必填.填了此字段就会验证证件号和姓名（暂只支持支付宝支付,微信支付(微信支付的刷卡支付除外)）
     * @param truename      <String> 实名，实名交易必填.填了此字段就会验证证件号和姓名（暂只支持支付宝支付,微信支付(微信支付的刷卡支付除外)）
     * @param asinfo        <String> 分账信息，开通此业务需开通分账配置（非必填）<br/>
     *                      格式: cusid:type:amount;cusid:type:amount;… <br/>
     *                      其中: cusid:接收分账的通联商户号, type:分账类型（01:按金额 02:按比率）如果分账类型为02, 则分账比率为0.5表示50%。如果分账类型为01，则分账金额以元为单位表示
     * @param extendparams  <String> 拓展参数，具体见接口文档 <br/>
     *                      https://aipboss.allinpay.com/know/devhelp/main.php?pid=15#mid=413
     * @param cusip         <String> 限云闪付JS支付业务（非必填）
     * @param fqnum         <String> 限支付宝分期业务（非必填）
     * @return Map<String, String>
     * @throws Exception Exception
     */
    public static Map<String, String> pay(long trxamt,
                                          String sn,
                                          String body,
                                          String remark,
                                          String acct,
                                          String notifyUrl,
                                          String limitPay,
                                          String appid,
                                          String subbranch,
                                          String paytype,
                                          String validTime,
                                          String goods_tag,
                                          String benefitdetail,
                                          String chnlstoreid,
                                          String idno,
                                          String truename,
                                          String asinfo,
                                          String extendparams,
                                          String cusip,
                                          String fqnum) throws Exception {

        HttpConnectionUtil http = new HttpConnectionUtil(SybConstants.SYB_APIURL + PAY_PATH);
        http.init();
        TreeMap<String, String> params = new TreeMap<>();
        // 集团/代理商商户号（共享集团号/代理商参数时必填）
        if (!SybUtil.isEmpty(SybConstants.SYB_ORGID)) {
            params.put("orgid", SybConstants.SYB_ORGID);
        }
        // 实际交易的商户号
        params.put("cusid", SybConstants.SYB_CUSID);
        // 平台分配的APPID
        params.put("appid", SybConstants.SYB_APPID);
        // 版本号（默认11）
        params.put("version", "11");
        params.put("trxamt", String.valueOf(trxamt));
        params.put("reqsn", sn);
        params.put("paytype", paytype);
        params.put("randomstr", SybUtil.getValidatecode(8));
        params.put("body", body);
        params.put("remark", remark);
        params.put("validtime", validTime);
        params.put("acct", acct);
        params.put("notify_url", notifyUrl);
        params.put("limit_pay", limitPay);
        params.put("sub_appid", appid);
        params.put("goods_tag", goods_tag);
        params.put("benefitdetail", benefitdetail);
        params.put("chnlstoreid", chnlstoreid);
        params.put("subbranch", subbranch);
        params.put("extendparams", extendparams);
        params.put("cusip", cusip);
        params.put("fqnum", fqnum);
        params.put("idno", idno);
        params.put("truename", truename);
        params.put("asinfo", asinfo);
        params.put("signtype", SybConstants.SIGN_TYPE);
        params.put("sign", SybUtil.unionSign(params, getAppKey(), SybConstants.SIGN_TYPE));

        System.out.println("请求接口:" + SybConstants.SYB_APIURL + PAY_PATH);

        System.out.println("请求参数:" + JSONUtil.toJsonStr(params));

        byte[] bys = http.postParams(params, true);
        String result = new String(bys, "UTF-8");

        System.out.println("响应结果:" + result);

        return handleResult(result);
    }

    public Map<String, String> cancel(long trxamt, String reqsn, String oldtrxid, String oldreqsn) throws Exception {
        // HttpConnectionUtil http = new HttpConnectionUtil(SybConstants.SYB_APIURL + CANCEL_PATH);
        // http.init();
        TreeMap<String, String> params = new TreeMap<>();
        if (!SybUtil.isEmpty(SybConstants.SYB_ORGID)) {
            params.put("orgid", SybConstants.SYB_ORGID);
        }
        params.put("cusid", SybConstants.SYB_CUSID);
        params.put("appid", SybConstants.SYB_APPID);
        params.put("version", "11");
        params.put("trxamt", String.valueOf(trxamt));
        params.put("reqsn", reqsn);
        params.put("oldtrxid", oldtrxid);
        params.put("oldreqsn", oldreqsn);
        params.put("randomstr", SybUtil.getValidatecode(8));
        params.put("signtype", SybConstants.SIGN_TYPE);

        params.put("sign", SybUtil.unionSign(params, getAppKey(), SybConstants.SIGN_TYPE));
        // byte[] bys = http.postParams(params, true);
        // String result = new String(bys, "UTF-8");
        String result = restTemplate.postForObject(SYB_APIURL + CANCEL_PATH, params, String.class);
        return handleResult(result);
    }

    public Map<String, String> refund(long trxamt, String reqsn, String oldtrxid, String oldreqsn) throws Exception {
        // HttpConnectionUtil http = new HttpConnectionUtil(SybConstants.SYB_APIURL + SybConstants.REFUND_PATH);
        // http.init();
        TreeMap<String, String> params = new TreeMap<>();
        if (!SybUtil.isEmpty(SybConstants.SYB_ORGID)) {
            params.put("orgid", SybConstants.SYB_ORGID);
        }
        params.put("cusid", SybConstants.SYB_CUSID);
        params.put("appid", SybConstants.SYB_APPID);
        params.put("version", "11");
        params.put("trxamt", String.valueOf(trxamt));
        params.put("reqsn", reqsn);
        params.put("oldreqsn", oldreqsn);
        params.put("oldtrxid", oldtrxid);
        params.put("randomstr", SybUtil.getValidatecode(8));
        params.put("signtype", SybConstants.SIGN_TYPE);

        params.put("sign", SybUtil.unionSign(params, getAppKey(), SybConstants.SIGN_TYPE));
        // byte[] bys = http.postParams(params, true);
        // String result = new String(bys, StandardCharsets.UTF_8);
        String result = restTemplate.postForObject(SYB_APIURL + SybConstants.REFUND_PATH, params, String.class);
        return handleResult(result);
    }

    public Map<String, String> query(String reqsn, String trxid) throws Exception {
        // HttpConnectionUtil http = new HttpConnectionUtil(SybConstants.SYB_APIURL + QUERY_PATH);
        // http.init();
        TreeMap<String, String> params = new TreeMap<String, String>();
        if (!SybUtil.isEmpty(SybConstants.SYB_ORGID))
            params.put("orgid", SybConstants.SYB_ORGID);
        params.put("cusid", SybConstants.SYB_CUSID);
        params.put("appid", SybConstants.SYB_APPID);
        params.put("version", "11");
        params.put("reqsn", reqsn);
        params.put("trxid", trxid);
        params.put("randomstr", SybUtil.getValidatecode(8));
        params.put("signtype", SybConstants.SIGN_TYPE);

        params.put("sign", SybUtil.unionSign(params, getAppKey(), SybConstants.SIGN_TYPE));
        // byte[] bys = http.postParams(params, true);
        // String result = new String(bys, "UTF-8");
        String result = restTemplate.postForObject(SYB_APIURL + QUERY_PATH, params, String.class);
        return handleResult(result);
    }

    /**
     * 支付回调处理
     *
     * @param result 回调信息
     * @return Map<String, String>
     * @throws Exception Exception
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public static Map<String, String> handleResult(String result) throws Exception {
        System.out.println("ret:" + result);
        Map map = SybUtil.json2Obj(result, Map.class);
        if (map == null) {
            throw new Exception("返回数据错误");
        }
        if ("SUCCESS".equals(map.get("retcode"))) {
            TreeMap tmap = new TreeMap(map);
            if (SybUtil.validSign(tmap, getAppKey(), SybConstants.SIGN_TYPE)) {
                System.out.println("签名成功");
                return map;
            } else {
                throw new Exception("验证签名失败");
            }

        } else {
            throw new Exception(map.get("retmsg").toString());
        }
    }

    /**
     * 扫码支付
     *
     * @param trxamt
     * @param reqsn
     * @param body
     * @param remark
     * @param authcode
     * @param limit_pay
     * @param idno
     * @param truename
     * @param asinfo
     * @return
     * @throws Exception
     */
    public Map<String, String> scanPay(long trxamt, String reqsn, String body, String remark, String authcode, String limit_pay, String idno, String truename, String asinfo) throws Exception {
        // HttpConnectionUtil http = new HttpConnectionUtil(SybConstants.SYB_APIURL + SCAN_QR_PAY_PATH);
        // http.init();
        TreeMap<String, String> params = new TreeMap<>();
        if (!SybUtil.isEmpty(SybConstants.SYB_ORGID)) {
            params.put("orgid", SybConstants.SYB_ORGID);
        }
        params.put("cusid", SybConstants.SYB_CUSID);
        params.put("appid", SybConstants.SYB_APPID);
        params.put("version", "11");
        params.put("trxamt", String.valueOf(trxamt));
        params.put("reqsn", reqsn);
        params.put("randomstr", SybUtil.getValidatecode(8));
        params.put("body", body);
        params.put("remark", remark);
        params.put("authcode", authcode);
        params.put("limit_pay", limit_pay);
        params.put("asinfo", asinfo);
        params.put("signtype", SybConstants.SIGN_TYPE);
        params.put("sign", SybUtil.unionSign(params, getAppKey(), SybConstants.SIGN_TYPE));
        // byte[] bys = http.postParams(params, true);
        // String result = new String(bys, "UTF-8");
        String result = restTemplate.postForObject(SYB_APIURL + SCAN_QR_PAY_PATH, params, String.class);
        return handleResult(result);
    }


}
